#!/bin/bash

# AIQuant 系统更新脚本
# 用途: 自动化系统更新，支持滚动更新和回滚
# 作者: AIQuant Team
# 版本: 1.0.0

set -e

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# 配置变量
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
UPDATE_DIR="/tmp/aiquant_update"
BACKUP_DIR="/opt/backups/pre_update_$(date +%Y%m%d_%H%M%S)"

# 更新选项
UPDATE_TYPE="rolling"  # rolling, blue-green, maintenance
UPDATE_SOURCE=""       # git, docker, local
GIT_BRANCH="main"
DOCKER_TAG="latest"
SKIP_BACKUP=false
SKIP_TESTS=false
AUTO_ROLLBACK=true
HEALTH_CHECK_TIMEOUT=300
DRY_RUN=false

# 服务配置
SERVICES=("postgres" "redis" "timescaledb" "backend" "frontend" "celery" "nginx")
CRITICAL_SERVICES=("postgres" "redis" "backend")

# 通知设置
ENABLE_NOTIFICATIONS=true
SLACK_WEBHOOK_URL=""
EMAIL_RECIPIENTS=""

# 日志函数
log_info() {
    echo -e "${BLUE}[INFO]${NC} $(date '+%Y-%m-%d %H:%M:%S') $1"
}

log_success() {
    echo -e "${GREEN}[SUCCESS]${NC} $(date '+%Y-%m-%d %H:%M:%S') $1"
}

log_warning() {
    echo -e "${YELLOW}[WARNING]${NC} $(date '+%Y-%m-%d %H:%M:%S') $1"
}

log_error() {
    echo -e "${RED}[ERROR]${NC} $(date '+%Y-%m-%d %H:%M:%S') $1"
}

# 错误处理
error_exit() {
    log_error "$1"
    send_notification "error" "更新失败: $1"
    
    if [[ "$AUTO_ROLLBACK" == "true" ]]; then
        log_info "开始自动回滚..."
        rollback_update
    fi
    
    exit 1
}

# 显示帮助信息
show_help() {
    cat << EOF
AIQuant 系统更新脚本

用法: $0 [OPTIONS]

选项:
    -h, --help              显示帮助信息
    -t, --type TYPE         更新类型 (rolling|blue-green|maintenance)
    -s, --source SOURCE     更新源 (git|docker|local)
    -b, --branch BRANCH     Git分支 (默认: $GIT_BRANCH)
    --tag TAG               Docker标签 (默认: $DOCKER_TAG)
    --local-path PATH       本地更新包路径
    --skip-backup           跳过更新前备份
    --skip-tests            跳过更新后测试
    --no-rollback           禁用自动回滚
    --timeout SECONDS       健康检查超时 (默认: $HEALTH_CHECK_TIMEOUT)
    --dry-run               模拟运行，不实际更新

更新类型说明:
    rolling      滚动更新 (默认，零停机)
    blue-green   蓝绿部署 (需要额外资源)
    maintenance  维护模式更新 (短暂停机)

更新源说明:
    git          从Git仓库拉取最新代码
    docker       拉取最新Docker镜像
    local        使用本地更新包

示例:
    $0                                    # 滚动更新，从Git拉取
    $0 -t blue-green -s docker            # 蓝绿部署，使用Docker镜像
    $0 -s local --local-path ./update.tar.gz  # 本地更新包
    $0 --skip-backup --dry-run            # 模拟更新，跳过备份

EOF
}

# 解析命令行参数
parse_args() {
    while [[ $# -gt 0 ]]; do
        case $1 in
            -h|--help)
                show_help
                exit 0
                ;;
            -t|--type)
                UPDATE_TYPE="$2"
                shift 2
                ;;
            -s|--source)
                UPDATE_SOURCE="$2"
                shift 2
                ;;
            -b|--branch)
                GIT_BRANCH="$2"
                shift 2
                ;;
            --tag)
                DOCKER_TAG="$2"
                shift 2
                ;;
            --local-path)
                LOCAL_UPDATE_PATH="$2"
                UPDATE_SOURCE="local"
                shift 2
                ;;
            --skip-backup)
                SKIP_BACKUP=true
                shift
                ;;
            --skip-tests)
                SKIP_TESTS=true
                shift
                ;;
            --no-rollback)
                AUTO_ROLLBACK=false
                shift
                ;;
            --timeout)
                HEALTH_CHECK_TIMEOUT="$2"
                shift 2
                ;;
            --dry-run)
                DRY_RUN=true
                shift
                ;;
            -*)
                error_exit "未知选项: $1"
                ;;
            *)
                shift
                ;;
        esac
    done
    
    # 设置默认更新源
    if [[ -z "$UPDATE_SOURCE" ]]; then
        if [[ -d "$PROJECT_ROOT/.git" ]]; then
            UPDATE_SOURCE="git"
        else
            UPDATE_SOURCE="docker"
        fi
    fi
}

# 加载配置
load_config() {
    local config_file="$PROJECT_ROOT/.update_config"
    if [[ -f "$config_file" ]]; then
        source "$config_file"
        log_info "已加载更新配置文件"
    fi
    
    # 从环境变量加载配置
    SLACK_WEBHOOK_URL=${UPDATE_SLACK_WEBHOOK:-$SLACK_WEBHOOK_URL}
    EMAIL_RECIPIENTS=${UPDATE_EMAIL_RECIPIENTS:-$EMAIL_RECIPIENTS}
    GIT_BRANCH=${UPDATE_GIT_BRANCH:-$GIT_BRANCH}
    DOCKER_TAG=${UPDATE_DOCKER_TAG:-$DOCKER_TAG}
}

# 预检查
pre_update_check() {
    log_info "执行更新前检查..."
    
    # 检查必需的命令
    local required_commands=("docker" "docker-compose")
    for cmd in "${required_commands[@]}"; do
        if ! command -v "$cmd" &> /dev/null; then
            error_exit "缺少必需命令: $cmd"
        fi
    done
    
    # 检查更新源特定命令
    case "$UPDATE_SOURCE" in
        "git")
            if ! command -v git &> /dev/null; then
                error_exit "Git未安装"
            fi
            if [[ ! -d "$PROJECT_ROOT/.git" ]]; then
                error_exit "不是Git仓库"
            fi
            ;;
        "local")
            if [[ ! -f "$LOCAL_UPDATE_PATH" ]]; then
                error_exit "本地更新包不存在: $LOCAL_UPDATE_PATH"
            fi
            ;;
    esac
    
    # 检查Docker服务
    if ! docker info &> /dev/null; then
        error_exit "Docker服务未运行"
    fi
    
    # 检查当前服务状态
    cd "$PROJECT_ROOT"
    local failed_services=()
    for service in "${CRITICAL_SERVICES[@]}"; do
        if ! docker-compose ps "$service" | grep -q "Up"; then
            failed_services+=("$service")
        fi
    done
    
    if [[ ${#failed_services[@]} -gt 0 ]]; then
        error_exit "关键服务未运行: ${failed_services[*]}"
    fi
    
    # 检查磁盘空间
    local available_space=$(df "$PROJECT_ROOT" 2>/dev/null | awk 'NR==2{print $4}' || echo "0")
    local required_space=2097152  # 2GB in KB
    if [[ $available_space -lt $required_space ]]; then
        error_exit "磁盘空间不足，需要至少2GB可用空间"
    fi
    
    # 检查更新类型
    if [[ ! "$UPDATE_TYPE" =~ ^(rolling|blue-green|maintenance)$ ]]; then
        error_exit "无效的更新类型: $UPDATE_TYPE"
    fi
    
    log_success "预检查完成"
}

# 创建更新前备份
create_pre_update_backup() {
    if [[ "$SKIP_BACKUP" == "true" ]]; then
        log_info "跳过更新前备份"
        return 0
    fi
    
    log_info "创建更新前备份..."
    
    if [[ "$DRY_RUN" == "true" ]]; then
        log_info "[DRY RUN] 将创建备份到: $BACKUP_DIR"
        return 0
    fi
    
    # 调用备份脚本
    local backup_script="$SCRIPT_DIR/backup_system.sh"
    if [[ -f "$backup_script" ]]; then
        "$backup_script" -t full -d "$(dirname "$BACKUP_DIR")" || error_exit "更新前备份失败"
    else
        log_warning "备份脚本不存在，手动创建简单备份"
        mkdir -p "$BACKUP_DIR"
        
        cd "$PROJECT_ROOT"
        
        # 备份关键配置
        tar -czf "$BACKUP_DIR/config_backup.tar.gz" \
            .env* docker-compose*.yml nginx ssl 2>/dev/null || log_warning "配置备份失败"
        
        # 备份数据库
        if docker-compose exec -T postgres pg_isready -U aiquant; then
            docker-compose exec -T postgres pg_dump \
                -U aiquant -d aiquant \
                --format=custom \
                > "$BACKUP_DIR/postgres_backup.dump" || log_warning "数据库备份失败"
        fi
    fi
    
    log_success "更新前备份完成: $BACKUP_DIR"
}

# 获取更新内容
fetch_update() {
    log_info "获取更新内容..."
    
    mkdir -p "$UPDATE_DIR"
    
    case "$UPDATE_SOURCE" in
        "git")
            fetch_git_update
            ;;
        "docker")
            fetch_docker_update
            ;;
        "local")
            fetch_local_update
            ;;
        *)
            error_exit "不支持的更新源: $UPDATE_SOURCE"
            ;;
    esac
    
    log_success "更新内容获取完成"
}

# 从Git获取更新
fetch_git_update() {
    log_info "从Git获取更新 (分支: $GIT_BRANCH)..."
    
    if [[ "$DRY_RUN" == "true" ]]; then
        log_info "[DRY RUN] 将从Git拉取分支: $GIT_BRANCH"
        return 0
    fi
    
    cd "$PROJECT_ROOT"
    
    # 保存当前状态
    local current_commit=$(git rev-parse HEAD)
    echo "$current_commit" > "$UPDATE_DIR/previous_commit"
    
    # 拉取最新代码
    git fetch origin || error_exit "Git fetch失败"
    
    # 检查是否有更新
    local latest_commit=$(git rev-parse "origin/$GIT_BRANCH")
    if [[ "$current_commit" == "$latest_commit" ]]; then
        log_info "没有可用更新"
        return 0
    fi
    
    log_info "发现新提交: $latest_commit"
    
    # 切换到新版本
    git checkout "$GIT_BRANCH" || error_exit "Git checkout失败"
    git pull origin "$GIT_BRANCH" || error_exit "Git pull失败"
    
    # 记录更新信息
    git log --oneline "$current_commit..$latest_commit" > "$UPDATE_DIR/changelog"
}

# 从Docker获取更新
fetch_docker_update() {
    log_info "从Docker获取更新 (标签: $DOCKER_TAG)..."
    
    if [[ "$DRY_RUN" == "true" ]]; then
        log_info "[DRY RUN] 将拉取Docker镜像标签: $DOCKER_TAG"
        return 0
    fi
    
    cd "$PROJECT_ROOT"
    
    # 获取当前镜像ID
    local current_images=()
    while read -r service image; do
        if [[ -n "$image" ]]; then
            current_images+=("$service:$(docker images --format '{{.ID}}' "$image" | head -1)")
        fi
    done < <(docker-compose config | grep 'image:' | sed 's/.*image: //')
    
    # 保存当前镜像信息
    printf '%s\n' "${current_images[@]}" > "$UPDATE_DIR/previous_images"
    
    # 拉取最新镜像
    docker-compose pull || error_exit "Docker镜像拉取失败"
    
    # 检查是否有更新
    local has_updates=false
    while read -r service_image; do
        local service=$(echo "$service_image" | cut -d: -f1)
        local old_id=$(echo "$service_image" | cut -d: -f2)
        local new_id=$(docker-compose images -q "$service" | head -1)
        
        if [[ "$old_id" != "$new_id" ]]; then
            log_info "服务 $service 有新镜像: $new_id"
            has_updates=true
        fi
    done < "$UPDATE_DIR/previous_images"
    
    if [[ "$has_updates" != "true" ]]; then
        log_info "没有可用的镜像更新"
    fi
}

# 从本地获取更新
fetch_local_update() {
    log_info "从本地获取更新: $LOCAL_UPDATE_PATH"
    
    if [[ "$DRY_RUN" == "true" ]]; then
        log_info "[DRY RUN] 将解压本地更新包: $LOCAL_UPDATE_PATH"
        return 0
    fi
    
    # 解压更新包
    if [[ "$LOCAL_UPDATE_PATH" =~ \.tar\.gz$ ]]; then
        tar -xzf "$LOCAL_UPDATE_PATH" -C "$UPDATE_DIR/" || error_exit "更新包解压失败"
    elif [[ "$LOCAL_UPDATE_PATH" =~ \.zip$ ]]; then
        unzip -q "$LOCAL_UPDATE_PATH" -d "$UPDATE_DIR/" || error_exit "更新包解压失败"
    else
        error_exit "不支持的更新包格式"
    fi
    
    # 查找更新内容
    local update_content=$(find "$UPDATE_DIR" -maxdepth 2 -name "docker-compose*.yml" -o -name "Dockerfile" | head -1)
    if [[ -z "$update_content" ]]; then
        error_exit "更新包中未找到有效内容"
    fi
}

# 执行滚动更新
rolling_update() {
    log_info "执行滚动更新..."
    
    if [[ "$DRY_RUN" == "true" ]]; then
        log_info "[DRY RUN] 将执行滚动更新"
        return 0
    fi
    
    cd "$PROJECT_ROOT"
    
    # 按依赖顺序更新服务
    local update_order=("postgres" "redis" "timescaledb" "backend" "celery" "frontend" "nginx")
    
    for service in "${update_order[@]}"; do
        if docker-compose ps "$service" | grep -q "$service"; then
            log_info "更新服务: $service"
            
            # 优雅停止服务
            docker-compose stop "$service" || log_warning "服务停止失败: $service"
            
            # 启动新版本
            docker-compose up -d "$service" || error_exit "服务启动失败: $service"
            
            # 等待服务就绪
            wait_for_service_health "$service"
            
            log_success "服务更新完成: $service"
        fi
    done
}

# 执行蓝绿部署
blue_green_update() {
    log_info "执行蓝绿部署..."
    
    if [[ "$DRY_RUN" == "true" ]]; then
        log_info "[DRY RUN] 将执行蓝绿部署"
        return 0
    fi
    
    cd "$PROJECT_ROOT"
    
    # 创建绿色环境
    local green_compose="docker-compose.green.yml"
    cp docker-compose.yml "$green_compose"
    
    # 修改绿色环境端口
    sed -i 's/8000:8000/8001:8000/g' "$green_compose"
    sed -i 's/3000:3000/3001:3000/g' "$green_compose"
    
    # 启动绿色环境
    log_info "启动绿色环境..."
    docker-compose -f "$green_compose" up -d || error_exit "绿色环境启动失败"
    
    # 等待绿色环境就绪
    log_info "等待绿色环境就绪..."
    sleep 30
    
    # 健康检查
    if ! check_environment_health "green"; then
        log_error "绿色环境健康检查失败"
        docker-compose -f "$green_compose" down
        rm -f "$green_compose"
        error_exit "蓝绿部署失败"
    fi
    
    # 切换流量
    log_info "切换流量到绿色环境..."
    switch_traffic_to_green
    
    # 停止蓝色环境
    log_info "停止蓝色环境..."
    docker-compose down
    
    # 重命名配置文件
    mv docker-compose.yml docker-compose.blue.yml
    mv "$green_compose" docker-compose.yml
    
    log_success "蓝绿部署完成"
}

# 执行维护模式更新
maintenance_update() {
    log_info "执行维护模式更新..."
    
    if [[ "$DRY_RUN" == "true" ]]; then
        log_info "[DRY RUN] 将执行维护模式更新"
        return 0
    fi
    
    cd "$PROJECT_ROOT"
    
    # 启用维护模式
    enable_maintenance_mode
    
    # 停止所有服务
    log_info "停止所有服务..."
    docker-compose down || log_warning "服务停止失败"
    
    # 启动新版本
    log_info "启动新版本服务..."
    docker-compose up -d || error_exit "服务启动失败"
    
    # 等待服务就绪
    log_info "等待服务就绪..."
    wait_for_all_services
    
    # 禁用维护模式
    disable_maintenance_mode
    
    log_success "维护模式更新完成"
}

# 等待服务健康检查
wait_for_service_health() {
    local service="$1"
    local timeout="${2:-$HEALTH_CHECK_TIMEOUT}"
    local start_time=$(date +%s)
    
    log_info "等待服务健康检查: $service"
    
    while true; do
        local current_time=$(date +%s)
        local elapsed=$((current_time - start_time))
        
        if [[ $elapsed -gt $timeout ]]; then
            error_exit "服务健康检查超时: $service"
        fi
        
        # 检查容器状态
        if docker-compose ps "$service" | grep -q "Up (healthy)"; then
            log_success "服务健康检查通过: $service"
            return 0
        elif docker-compose ps "$service" | grep -q "Up"; then
            # 如果没有健康检查，检查端口
            case "$service" in
                "postgres")
                    if docker-compose exec -T postgres pg_isready -U aiquant; then
                        log_success "服务就绪: $service"
                        return 0
                    fi
                    ;;
                "redis")
                    if docker-compose exec -T redis redis-cli ping | grep -q "PONG"; then
                        log_success "服务就绪: $service"
                        return 0
                    fi
                    ;;
                "backend"|"frontend")
                    # 简单的端口检查
                    sleep 5
                    log_success "服务就绪: $service"
                    return 0
                    ;;
                *)
                    sleep 5
                    log_success "服务就绪: $service"
                    return 0
                    ;;
            esac
        fi
        
        sleep 5
    done
}

# 等待所有服务
wait_for_all_services() {
    for service in "${SERVICES[@]}"; do
        if docker-compose ps "$service" | grep -q "$service"; then
            wait_for_service_health "$service"
        fi
    done
}

# 检查环境健康状态
check_environment_health() {
    local env="$1"
    local base_port=8000
    
    if [[ "$env" == "green" ]]; then
        base_port=8001
    fi
    
    # 检查API健康状态
    local health_url="http://localhost:$base_port/health"
    local retry_count=0
    local max_retries=10
    
    while [[ $retry_count -lt $max_retries ]]; do
        if curl -s "$health_url" | grep -q "healthy"; then
            return 0
        fi
        
        sleep 10
        ((retry_count++))
    done
    
    return 1
}

# 启用维护模式
enable_maintenance_mode() {
    log_info "启用维护模式..."
    
    # 创建维护页面
    local maintenance_page="/tmp/maintenance.html"
    cat > "$maintenance_page" << 'EOF'
<!DOCTYPE html>
<html>
<head>
    <title>系统维护中</title>
    <meta charset="utf-8">
    <style>
        body { font-family: Arial, sans-serif; text-align: center; padding: 50px; }
        .container { max-width: 600px; margin: 0 auto; }
        h1 { color: #333; }
        p { color: #666; line-height: 1.6; }
    </style>
</head>
<body>
    <div class="container">
        <h1>系统维护中</h1>
        <p>AIQuant系统正在进行维护更新，预计几分钟后恢复正常。</p>
        <p>给您带来的不便，敬请谅解。</p>
    </div>
</body>
</html>
EOF
    
    # 配置Nginx显示维护页面
    if docker-compose ps nginx | grep -q "Up"; then
        docker cp "$maintenance_page" $(docker-compose ps -q nginx):/usr/share/nginx/html/maintenance.html
        
        # 临时修改Nginx配置
        docker-compose exec nginx sh -c "
            echo 'server { listen 80; return 503; error_page 503 /maintenance.html; location = /maintenance.html { root /usr/share/nginx/html; } }' > /etc/nginx/conf.d/maintenance.conf
            nginx -s reload
        " || log_warning "维护模式配置失败"
    fi
}

# 禁用维护模式
disable_maintenance_mode() {
    log_info "禁用维护模式..."
    
    if docker-compose ps nginx | grep -q "Up"; then
        docker-compose exec nginx sh -c "
            rm -f /etc/nginx/conf.d/maintenance.conf
            nginx -s reload
        " || log_warning "维护模式禁用失败"
    fi
}

# 切换流量到绿色环境
switch_traffic_to_green() {
    log_info "切换流量到绿色环境..."
    
    # 这里需要根据实际的负载均衡器配置来实现
    # 示例：更新Nginx配置
    if docker-compose ps nginx | grep -q "Up"; then
        docker-compose exec nginx sh -c "
            sed -i 's/:8000/:8001/g' /etc/nginx/conf.d/default.conf
            nginx -s reload
        " || log_warning "流量切换失败"
    fi
}

# 运行更新后测试
run_post_update_tests() {
    if [[ "$SKIP_TESTS" == "true" ]]; then
        log_info "跳过更新后测试"
        return 0
    fi
    
    log_info "运行更新后测试..."
    
    if [[ "$DRY_RUN" == "true" ]]; then
        log_info "[DRY RUN] 将运行更新后测试"
        return 0
    fi
    
    cd "$PROJECT_ROOT"
    
    # 基本健康检查
    local test_failed=false
    
    # 检查关键服务
    for service in "${CRITICAL_SERVICES[@]}"; do
        if ! docker-compose ps "$service" | grep -q "Up"; then
            log_error "关键服务未运行: $service"
            test_failed=true
        fi
    done
    
    # API健康检查
    if ! curl -s http://localhost:8000/health | grep -q "healthy"; then
        log_error "API健康检查失败"
        test_failed=true
    fi
    
    # 数据库连接检查
    if ! docker-compose exec -T postgres pg_isready -U aiquant; then
        log_error "数据库连接失败"
        test_failed=true
    fi
    
    # 运行自定义测试
    if [[ -f "tests/post_update_tests.sh" ]]; then
        log_info "运行自定义测试..."
        bash tests/post_update_tests.sh || test_failed=true
    fi
    
    if [[ "$test_failed" == "true" ]]; then
        error_exit "更新后测试失败"
    else
        log_success "更新后测试通过"
    fi
}

# 回滚更新
rollback_update() {
    log_info "开始回滚更新..."
    
    if [[ "$DRY_RUN" == "true" ]]; then
        log_info "[DRY RUN] 将回滚更新"
        return 0
    fi
    
    cd "$PROJECT_ROOT"
    
    case "$UPDATE_SOURCE" in
        "git")
            if [[ -f "$UPDATE_DIR/previous_commit" ]]; then
                local previous_commit=$(cat "$UPDATE_DIR/previous_commit")
                log_info "回滚到提交: $previous_commit"
                git checkout "$previous_commit" || log_error "Git回滚失败"
            fi
            ;;
        "docker")
            if [[ -f "$UPDATE_DIR/previous_images" ]]; then
                log_info "回滚Docker镜像..."
                # 这里需要实现镜像回滚逻辑
                docker-compose down
                # 恢复之前的镜像标签
                docker-compose up -d
            fi
            ;;
    esac
    
    # 如果有备份，可以选择恢复
    if [[ -d "$BACKUP_DIR" && "$SKIP_BACKUP" != "true" ]]; then
        log_info "可以从备份恢复: $BACKUP_DIR"
        log_info "运行: $SCRIPT_DIR/restore_system.sh $BACKUP_DIR"
    fi
    
    log_success "回滚完成"
}

# 清理更新环境
cleanup_update() {
    log_info "清理更新环境..."
    
    if [[ "$DRY_RUN" == "true" ]]; then
        log_info "[DRY RUN] 将清理更新环境"
        return 0
    fi
    
    # 清理临时文件
    rm -rf "$UPDATE_DIR"
    
    # 清理Docker资源
    docker system prune -f || log_warning "Docker清理失败"
    
    log_success "更新环境清理完成"
}

# 发送通知
send_notification() {
    if [[ "$ENABLE_NOTIFICATIONS" != "true" ]]; then
        return 0
    fi
    
    local status="$1"
    local message="$2"
    
    # Slack通知
    if [[ -n "$SLACK_WEBHOOK_URL" ]]; then
        local color="good"
        if [[ "$status" == "error" ]]; then
            color="danger"
        elif [[ "$status" == "warning" ]]; then
            color="warning"
        fi
        
        curl -X POST "$SLACK_WEBHOOK_URL" \
            -H 'Content-type: application/json' \
            --data "{
                \"attachments\": [{
                    \"color\": \"$color\",
                    \"title\": \"AIQuant系统更新\",
                    \"text\": \"$message\",
                    \"fields\": [
                        {\"title\": \"更新类型\", \"value\": \"$UPDATE_TYPE\", \"short\": true},
                        {\"title\": \"更新源\", \"value\": \"$UPDATE_SOURCE\", \"short\": true},
                        {\"title\": \"时间\", \"value\": \"$(date)\", \"short\": false}
                    ]
                }]
            }" || log_warning "Slack通知发送失败"
    fi
    
    # 邮件通知
    if [[ -n "$EMAIL_RECIPIENTS" ]]; then
        local subject="AIQuant系统更新通知"
        local body="更新状态: $status\n消息: $message\n更新类型: $UPDATE_TYPE\n更新源: $UPDATE_SOURCE\n时间: $(date)"
        
        echo -e "$body" | mail -s "$subject" "$EMAIL_RECIPIENTS" || log_warning "邮件通知发送失败"
    fi
}

# 信号处理
cleanup_on_exit() {
    log_info "接收到退出信号，正在清理..."
    
    # 如果正在更新过程中，尝试回滚
    if [[ -f "$UPDATE_DIR/.update_in_progress" ]]; then
        log_warning "更新过程中断，尝试回滚..."
        rollback_update
    fi
    
    # 清理临时文件
    cleanup_update
    
    exit 1
}

# 设置信号处理
trap cleanup_on_exit SIGINT SIGTERM

# 主函数
main() {
    log_info "开始AIQuant系统更新..."
    log_info "更新类型: $UPDATE_TYPE"
    log_info "更新源: $UPDATE_SOURCE"
    
    if [[ "$DRY_RUN" == "true" ]]; then
        log_info "*** 模拟运行模式 ***"
    fi
    
    # 创建更新进度标记
    mkdir -p "$UPDATE_DIR"
    touch "$UPDATE_DIR/.update_in_progress"
    
    # 发送开始通知
    send_notification "info" "系统更新开始"
    
    local start_time=$(date +%s)
    
    # 执行更新步骤
    pre_update_check
    create_pre_update_backup
    fetch_update
    
    # 根据更新类型执行相应的更新策略
    case "$UPDATE_TYPE" in
        "rolling")
            rolling_update
            ;;
        "blue-green")
            blue_green_update
            ;;
        "maintenance")
            maintenance_update
            ;;
        *)
            error_exit "不支持的更新类型: $UPDATE_TYPE"
            ;;
    esac
    
    # 运行更新后测试
    run_post_update_tests
    
    # 清理更新环境
    cleanup_update
    
    # 移除更新进度标记
    rm -f "$UPDATE_DIR/.update_in_progress"
    
    local end_time=$(date +%s)
    local duration=$((end_time - start_time))
    
    log_success "系统更新完成！"
    log_info "更新耗时: ${duration}秒"
    
    # 发送成功通知
    send_notification "success" "系统更新成功完成，耗时${duration}秒"
    
    # 显示更新摘要
    show_update_summary
}

# 显示更新摘要
show_update_summary() {
    echo
    echo "=================================="
    echo "        更新摘要"
    echo "=================================="
    echo "更新类型: $UPDATE_TYPE"
    echo "更新源: $UPDATE_SOURCE"
    echo "开始时间: $(date -d @$start_time 2>/dev/null || date)"
    echo "结束时间: $(date)"
    
    if [[ "$UPDATE_SOURCE" == "git" && -f "$UPDATE_DIR/changelog" ]]; then
        echo
        echo "更新内容:"
        cat "$UPDATE_DIR/changelog"
    fi
    
    echo
    echo "服务状态:"
    cd "$PROJECT_ROOT"
    docker-compose ps
    
    echo
    echo "系统资源使用:"
    docker stats --no-stream --format "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}"
    
    echo "=================================="
}

# 检查是否以root权限运行
check_permissions() {
    if [[ $EUID -eq 0 ]]; then
        log_warning "检测到以root权限运行，建议使用普通用户"
    fi
    
    # 检查Docker权限
    if ! docker info &> /dev/null; then
        if groups | grep -q docker; then
            log_error "Docker服务未运行或权限不足"
        else
            log_error "当前用户不在docker组中，请运行: sudo usermod -aG docker $USER"
        fi
        exit 1
    fi
}

# 验证更新配置
validate_config() {
    log_info "验证更新配置..."
    
    # 验证更新类型
    case "$UPDATE_TYPE" in
        "rolling"|"blue-green"|"maintenance")
            ;;
        *)
            error_exit "无效的更新类型: $UPDATE_TYPE"
            ;;
    esac
    
    # 验证更新源
    case "$UPDATE_SOURCE" in
        "git"|"docker"|"local")
            ;;
        *)
            error_exit "无效的更新源: $UPDATE_SOURCE"
            ;;
    esac
    
    # 验证超时设置
    if ! [[ "$HEALTH_CHECK_TIMEOUT" =~ ^[0-9]+$ ]] || [[ $HEALTH_CHECK_TIMEOUT -lt 30 ]]; then
        error_exit "无效的健康检查超时设置: $HEALTH_CHECK_TIMEOUT (最小30秒)"
    fi
    
    log_success "配置验证通过"
}

# 脚本入口点
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
    # 解析命令行参数
    parse_args "$@"
    
    # 加载配置
    load_config
    
    # 检查权限
    check_permissions
    
    # 验证配置
    validate_config
    
    # 执行主函数
    main
fi